package com.zmj.sy.mom.srv.aps.utils.ado;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zmj.sy.mom.srv.aps.bean.bo.ado.*;
import com.zmj.sy.mom.srv.aps.bean.entity.aps.AdoOrder;
import com.zmj.sy.mom.srv.aps.bean.entity.aps.AdoWorkDetail;
import com.zmj.sy.mom.srv.aps.bean.entity.base.BaseEntity;
import com.zmj.sy.mom.srv.aps.bean.entity.order.Order;
import com.zmj.sy.mom.srv.aps.bean.entity.order.OrderBom;
import com.zmj.sy.mom.srv.aps.bean.entity.order.OrderPhase;
import com.zmj.sy.mom.srv.aps.bean.entity.resource.*;
import com.zmj.sy.mom.srv.aps.bean.vo.dayworkorder.ApsDayOrderPhaseEditReqVo;
import com.zmj.sy.mom.srv.aps.bean.vo.dayworkorder.DayWorkOrderPhaseEditItemReqVo;
import com.zmj.sy.mom.srv.aps.config.ProjectConfig;
import com.zmj.sy.mom.srv.aps.mapper.*;
import com.zmj.sy.mom.srv.aps.utils.ApsConstant;
import com.zmj.sy.mom.srv.aps.utils.JsonUtils;
import com.zmj.sy.mom.srv.aps.utils.PkgUtils;
import com.zmj.sy.mom.srv.aps.utils.SyExceptionUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@RequiredArgsConstructor
@Component
public class DefaultApsDayOrderRule implements ApsDayOrderRule {

    private final StringRedisTemplate stringRedisTemplate;
    private final OrderMapper orderMapper;
    private final ApsDayWorkOrderMapper apsDayWorkOrderMapper;
    private final OrderBomMapper orderBomMapper;
    private final OrderPhaseMapper orderPhaseMapper;
    private final DayWorkDetailMapper dayWorkDetailMapper;

    private final ProjectConfig projectConfig;
    private final GroupMapper groupMapper;
    private final StationMapper stationMapper;
    private final ShiftTypeMapper shiftTypeMapper;
    private final ShiftMapper shiftMapper;
    private final WeekdayRuleMapper weekdayRuleMapper;
    private final BreakPeriodMapper breakPeriodMapper;

    private final ProjectConfig projectConig;
    private final PhaseMapper phaseMapper;
    private final ApsDetailWeekdayMapper apsDetailWeekdayMapper;
    private final AdoWorkDetailMapper adoWorkDetailMapper;
    private final AdoOrderMapper adoOrderMapper;


    @Transactional
    @Override
    public void process(List<Order> orderList, ApsDayOrderPhaseEditReqVo reqVo) {
        // 检查redis是否有锁定状态，如果有则提示，并且不排产
        ValueOperations<String, String> valOperation = stringRedisTemplate.opsForValue();
        String lockFlag = valOperation.get(ApsConstant.APS_SCHEDULING_LOCK);
        if (StringUtils.hasText(lockFlag)) {
            throw SyExceptionUtils.e("{} 等订单排产中!", lockFlag);
        }

        try {
            reScheduling(reqVo);
        } finally {
            unlock(reqVo);
        }
    }

    public void reScheduling(ApsDayOrderPhaseEditReqVo reqVo) {
        log.info("scheduling reqVo: {}", JsonUtils.toJsonString(reqVo));

        AdoFactoryCache factoryCache = new AdoFactoryCache();
        AdoOrderCache orderCache = new AdoOrderCache();

//        initOrderCache(factoryCache, orderCache, reqVo);

        initOrderCache(factoryCache, orderCache, reqVo);

        initFactoryCache(factoryCache, orderCache, reqVo);

        scheduleTask(factoryCache, orderCache);

        saveAndUpateRe(orderCache);

    }

    public void saveAndUpateRe(AdoOrderCache orderCache) {
        List<AdoOrder> adoOrderList = orderCache.getAdoOrderTempList().stream().map(AdoOrderTemp::getAdoOrder).collect(Collectors.toList());
        adoOrderMapper.insertBatch(adoOrderList);

        List<AdoWorkDetail> collect = orderCache.getTaskList().stream().map(e -> {
                    AdoWorkDetailTemp workDetailTemp = e.getWorkDetailTemp();
                    workDetailTemp.getWorkDetail().setAdoOrderId(workDetailTemp.getAdoOrderTemp().getAdoOrder().getId());
                    return workDetailTemp.getWorkDetail();
                })
                .collect(Collectors.toList());
        adoWorkDetailMapper.insertBatch(collect);


    }

    public void scheduleTask(AdoFactoryCache factoryCache, AdoOrderCache orderCache) {

//        List<ApsDayOrder> dayOrderList = orderCache.getDayOrderList();
//        Collections.reverse(dayOrderList);

//        orderCache.getTaskList().stream().collect(Collectors.groupingBy(e -> e.getWorkDetailTemp().getApsDayOrder().getWorkDate(), Collectors.groupingBy(e -> e.getWorkDetailTemp().getOrderBom().getLevel())));
//        Map<LocalDate, List<AdoTask>> taskAdoOrderMap = orderCache.getTaskList().stream().collect(Collectors.groupingBy(e -> e.getWorkDetailTemp().getApsDayOrder().getWorkDate()));
//        Map<Integer, List<AdoTask>> allMap = orderCache.getTaskList().stream().collect(Collectors.groupingBy(e -> e.getWorkDetailTemp().getAdoOrderTemp().getId()));

        Map<Integer, Map<Integer, List<AdoTask>>> allMap = orderCache.getTaskList().stream().collect(Collectors.groupingBy(e -> e.getWorkDetailTemp().getAdoOrderTemp().getId(), Collectors.groupingBy(e -> e.getWorkDetailTemp().getOrderBom().getLevel())));
        Map<Integer, AdoOrderTemp> adoOrderTempMap = orderCache.getAdoOrderTempList().stream().collect(Collectors.toMap(AdoOrderTemp::getId, e -> e));
        Map<Integer, Map<Integer, Map<Integer, List<AdoTask>>>> apsTaskWorkOrderIdPhaseSeqMap = orderCache.getTaskList().stream().collect(Collectors.groupingBy(e -> e.getWorkDetailTemp().getAdoOrderTemp().getId(), Collectors.groupingBy(e -> e.getWorkDetailTemp().getOrderBom().getId(), Collectors.groupingBy(e -> e.getWorkDetailTemp().getWorkDetail().getPhaseSeq()))));


        List<AdoOrderTemp> adoOrderTempList = allMap.keySet().stream().map(adoOrderTempMap::get).sorted(Comparator.comparingInt(e -> e.getAdoOrder().getSeq())).collect(Collectors.toList());

        List<String> lines = new ArrayList<>();
        for (AdoOrderTemp adoOrderTemp : adoOrderTempList) {
            Map<Integer, List<AdoTask>> integerListMap = allMap.get(adoOrderTemp.getId());

            Set<Integer> integers = integerListMap.keySet();
            List<Integer> seqList = integers.stream().sorted(Comparator.comparing(e -> e)).collect(Collectors.toList());
            Integer rootLevel = null;
            for (Integer seq : seqList) {
                if(rootLevel == null){
                    rootLevel = seq;
                }
                List<AdoTask> levelTask = integerListMap.get(seq);

                Map<Integer, List<AdoTask>> collect = levelTask.stream().collect(Collectors.groupingBy(e -> e.getWorkDetailTemp().getOrderBom().getId()));
                Map<String, Map<String, Integer>> phaseGroupWorkTimeMap = calcPhaseGroupWorkTimeMap(new ArrayList<>(collect.keySet()), adoOrderTemp, orderCache, factoryCache, apsTaskWorkOrderIdPhaseSeqMap, lines);
                for (Integer bomId : collect.keySet()) {
                    List<AdoTask> bomTask = collect.get(bomId);
                    bomTask.sort(Comparator.comparing(e -> e.getWorkDetail().getPhaseSeq()));

                    phaseList(rootLevel, bomId, adoOrderTemp, orderCache, factoryCache, apsTaskWorkOrderIdPhaseSeqMap, null, phaseGroupWorkTimeMap);
                }

            }

        }


    }


    public Map<String, Map<String, Integer>> calcPhaseGroupWorkTimeMap(List<Integer> parentWorkOrder, AdoOrderTemp apsOrder, AdoOrderCache orderCache, AdoFactoryCache factoryCache, Map<Integer, Map<Integer, Map<Integer, List<AdoTask>>>> apsTaskWorkOrderIdPhaseSeqMap, List<String> lines) {
//        orderCache.get
//        Integer level = parentWorkOrder.get(0).getApsWorkOrder().getLevel();
//        List<ApsWorkOrderTemp> collect = parentWorkOrder.stream().filter(e -> e.getApsWorkOrder().getLevel().equals(level)).collect(Collectors.toList());

        Map<String, Map<String, Integer>> phaseGroupWorkTimeMap = new HashMap<>();

        for (Integer bomId : parentWorkOrder) {
            OrderBom orderBom = orderCache.getOrderBomIdMap().get(bomId);
//            phaseGroupWorkTimeMap.put(apsWorkOrderTemp.getApsWorkOrder().getPhaseCode(), new HashMap<>());

            Map<Integer, List<AdoTask>> phaseSeqMap = apsTaskWorkOrderIdPhaseSeqMap.get(apsOrder.getId()).get(bomId);
            if (CollUtil.isEmpty(phaseSeqMap) && orderBom.getWorkChain().equals("WL")) {
                continue;
            }
            if (phaseSeqMap == null) {
                throw SyExceptionUtils.e("工单号：{}，PLMID：{}，物料号：{} 没有可执行工序", orderBom.getWorkOrderCode(), orderBom.getPlmId(), orderBom.getPlmId());
            }
            List<Integer> phaseSeqKey = new ArrayList<>(phaseSeqMap.keySet());
            phaseSeqKey.sort(Comparator.comparingInt(e -> -e));

            for (int i = 0; i < phaseSeqKey.size(); i++) {
                Integer phaseSeq = phaseSeqKey.get(i);
                List<AdoTask> taskList = phaseSeqMap.get(phaseSeq).stream().filter(e -> e.getWorkDetailTemp().getAdoOrderTemp().getId().equals(apsOrder.getId())).collect(Collectors.toList());

                if (!orderBom.getMaterType().equals("Assembly")) {
                    Integer reduce = taskList.stream()
                            .map(e -> e.getWorkDetail().getWorkTime() * e.getWorkDetail().getOrderCount().intValue())
                            .reduce(Integer::sum)
                            .get();

                    AdoWorkDetail adwd = taskList.get(0).getWorkDetail();

                    Integer newVal = phaseGroupWorkTimeMap.getOrDefault(adwd.getPhaseCode(), new HashMap<>())
                            .compute(adwd.getGroupCode(), (k, v) -> (v == null) ? reduce : v + reduce);
                    phaseGroupWorkTimeMap.computeIfAbsent(adwd.getPhaseCode(), k -> new HashMap<>());
                    phaseGroupWorkTimeMap.get(adwd.getPhaseCode()).put(adwd.getGroupCode(), newVal);
                }
            }
        }

        return phaseGroupWorkTimeMap;
    }

    public void phaseList(Integer rootLevel, Integer bomId, AdoOrderTemp adoOrderTemp, AdoOrderCache orderCache, AdoFactoryCache factoryCache, Map<Integer, Map<Integer, Map<Integer, List<AdoTask>>>> apsTaskWorkOrderIdPhaseSeqMap, Object o1, Map<String, Map<String, Integer>> phaseGroupWorkTimeMap) {
        Map<Integer, List<AdoTask>> phaseSeqMap = apsTaskWorkOrderIdPhaseSeqMap.get(adoOrderTemp.getId()).get(bomId);
        OrderBom orderBom = orderCache.getOrderBomIdMap().get(bomId);

        List<Integer> phaseSeqKey = new ArrayList<>(phaseSeqMap.keySet());
        phaseSeqKey.sort(Comparator.comparingInt(e -> -e));

        for (int i = 0; i < phaseSeqKey.size(); i++) {
            Integer phaseSeq = phaseSeqKey.get(i);
            List<AdoTask> taskList = phaseSeqMap.get(phaseSeq);

            if (i == 0 && orderBom.getLevel().equals(rootLevel)) {
                // 如果没有顶层，则取包的结束时间
                LocalDate deliveryDate = adoOrderTemp.getAdoOrder().getWorkDate();
                for (AdoTask adoTask : taskList) {
                    adoTask.getWorkDetail().setPlanEndDateTime(LocalDateTime.of(deliveryDate.plusDays(1), LocalTime.of(0, 0, 0, 0)));
                }
            } else if (i == 0) {
                // 获取顶层的工单时间
                Map<Integer, List<AdoTask>> parentPhaseSeqMap = apsTaskWorkOrderIdPhaseSeqMap.get(adoOrderTemp.getId()).get(orderBom.getPid());
                List<AdoTask> parentTaskList = parentPhaseSeqMap.get(new LinkedList<>(parentPhaseSeqMap.keySet()).getFirst());

                int partCount = orderBom.getTotalCount().multiply(new BigDecimal(adoOrderTemp.getAdoOrder().getTotalCount())).intValue();

                List<AdoTask> collect = parentTaskList.stream()
                        .sorted(Comparator.comparing((AdoTask e) -> e.getWorkDetail().getPlanStartDateTime()).reversed())
                        .flatMap(e -> Stream.iterate(e, e1 -> e1).limit(partCount))
                        .collect(Collectors.toList());

                int last = 0;
                for (AdoTask task : taskList) {
                    BigDecimal totalCount = task.getWorkDetail().getOrderCount();
                    Optional<LocalDateTime> min = collect.stream().map(e -> e.getWorkDetail().getPlanStartDateTime()).skip(last).limit(totalCount.intValue()).min(Comparator.comparing(e -> e));
                    if (min.isPresent()) {
                        task.getWorkDetail().setPlanEndDateTime(min.get());
                        last += totalCount.intValue();
                    }
                }
            } else {
                // 获取前一道工序的时间
                List<AdoTask> preTask = phaseSeqMap.get(phaseSeqKey.get(i - 1));
                AdoTask apsTask = preTask.stream().min(Comparator.comparing((AdoTask e) -> e.getWorkDetail().getPlanStartDateTime())).get();

                for (AdoTask task : taskList) {
                    task.getWorkDetail().setPlanEndDateTime(apsTask.getWorkDetail().getPlanStartDateTime());
                }

            }

            List<AdoMachine> machines = factoryCache.getGroupCodeMachineMap().get(taskList.get(0).getWorkDetail().getGroupCode());
            if (CollUtil.isEmpty(machines)) {
                throw SyExceptionUtils.e("没有找到工作组:[" + factoryCache.getGroupCodeMachineMap().get(taskList.get(0).getWorkDetail().getGroupCode() + "], 对应的工序:[" + factoryCache.getGroupCodeMachineMap().get(taskList.get(0).getWorkDetail().getPhaseCode() + "]")));
            }

            for (AdoTask currentTask : taskList) {

                List<AdoDetailWeekdayWrap> l = new ArrayList<>();
                LocalDateTime start = currentTask.getWorkDetail().getPlanEndDateTime();
                currentTask.getWorkDetail().setPlanEndDateTime(null);

                for (AdoMachine machine : machines) {
                    AdoDetailWeekdayWrap scheduling = AdoTaskUtils.scheduling(factoryCache, orderCache, start, machine, currentTask, apsDetailWeekdayMapper, adoWorkDetailMapper, l, machines, phaseGroupWorkTimeMap);
                    l.add(scheduling);
                }

                AdoDetailWeekdayWrap calendarWrap = l.stream().max(Comparator.comparing(AdoDetailWeekdayWrap::getStartDateTime)).orElseThrow(() -> SyExceptionUtils.e("排产异常"));
                currentTask.getWorkDetail().setPlanStartDateTime(calendarWrap.getStartDateTime());
                currentTask.getWorkDetail().setPlanEndDateTime(calendarWrap.getEndDateTime());
                currentTask.setNextTask(calendarWrap.getNext());
                calendarWrap.getPrevious().setNextTask(currentTask);
                currentTask.getWorkDetail().setStationId(calendarWrap.getMachine().getId());
                currentTask.setStartMachineCalendar(calendarWrap.getStartMachineCalendar());
                currentTask.setAll(calendarWrap.getAll());
                currentTask.getWorkDetail().setStatus(2);
                currentTask.setStatus(5);
                calendarWrap.getMachine().setNextTask(null);

                System.out.println(String.format("包号:%s, 零件名称:%s, PLMID:%s, 工序:%s, 开始时间:%s, 结束时间:%s, 工位:%s, 工作组:%s, 数量:%s, 工位数量:%s",
                        PkgUtils.gen(currentTask.getWorkDetailTemp().getAdoOrderTemp().getAdoOrder().getSeq()),
                        currentTask.getWorkDetail().getMaterName(),
                        currentTask.getWorkDetail().getPlmId(),
                        currentTask.getWorkDetail().getPhaseCode(),
                        currentTask.getWorkDetail().getPlanStartDateTime() == null? "": currentTask.getWorkDetail().getPlanStartDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
                        currentTask.getWorkDetail().getPlanEndDateTime() == null? "": currentTask.getWorkDetail().getPlanEndDateTime().format(DatePattern.NORM_DATETIME_FORMATTER),
                        currentTask.getWorkDetail().getStationId(),
                        currentTask.getWorkDetail().getGroupCode(),
                        currentTask.getWorkDetail().getOrderCount().intValue(),
                        machines.size()
                ));

            }


        }

//        AdoTask minTask = phaseSeqMap.values().stream().flatMap(List::stream).min(Comparator.comparing(AdoTask::getWorkDetail, Comparator.comparing(ApsDayWorkDetail::getPlanStartDateTime))).get();
//        AdoTask maxTask = phaseSeqMap.values().stream().flatMap(List::stream).max(Comparator.comparing(AdoTask::getWorkDetail, Comparator.comparing(ApsDayWorkDetail::getPlanEndDateTime))).get();
//        workOrderTemp.getApsWorkOrder().setPlanStartDateTime(minTask.getPlanStartDateTime());
//        workOrderTemp.getApsWorkOrder().setPlanEndDateTime(maxTask.getPlanEndDateTime());

    }


    public void initFactoryCache(AdoFactoryCache factoryCache, AdoOrderCache orderCache, ApsDayOrderPhaseEditReqVo reqVo) {

        // 设置工厂信息
        factoryCache.setFactoryCode(projectConfig.getFactoryCode());

        // 工作组信息
        List<String> groupNumberString = orderPhaseMapper.selectGroupList(Wrappers.<OrderPhase>query()
                .in("order_id", orderCache.getOrder().getId())
        );
        List<Group> groups = groupMapper.lambdaQuery().in(Group::getMyCode, groupNumberString).list();
        factoryCache.setGroups(groups);

        // 工位信息
        List<Integer> groupIds = groups.stream().map(BaseEntity::getId).collect(Collectors.toList());
        List<Station> stations = stationMapper.lambdaQuery().in(Station::getGroupId, groupIds).list();
        for (Station station : stations) {
            if (station.getEnterTime() == null || station.getEnterTime() < 0) {
                station.setEnterTime(0);
            }

            if (station.getOutTime() == null || station.getOutTime() < 0) {
                station.setOutTime(0);
            }

            if (station.getChangTime() == null || station.getChangTime() < 0) {
                station.setChangTime(0);
            }
        }

        factoryCache.setStations(stations);

        // 工位日历
        List<Integer> shiftTypeIds = groups.stream().map(Group::getShiftTypeId).distinct().collect(Collectors.toList());
        List<ShiftType> shiftTypes = shiftTypeMapper.selectBatchIds(shiftTypeIds);
        List<Shift> shifts = shiftMapper.lambdaQuery().in(Shift::getShiftTypeId, shiftTypeIds).list();
        List<WeekdayRule> weekdayRules = weekdayRuleMapper.lambdaQuery().in(WeekdayRule::getShiftTypeId, shiftTypeIds).list();
        List<BreakPeriod> breakPeriods = breakPeriodMapper.lambdaQuery().in(BreakPeriod::getShiftId, shifts.stream().map(BaseEntity::getId).distinct().collect(Collectors.toList())).list();

        Map<Integer, Shift> shiftIdMap = shifts.stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));

        factoryCache.setWeekdayRules(weekdayRules);
        factoryCache.setShiftTypes(shiftTypes);
        factoryCache.setShifts(shifts);
        factoryCache.setBreakPeriods(breakPeriods);

        // 拼装设备时间链
        LocalDate startDate = reqVo.getItems().stream().min(Comparator.comparing(DayWorkOrderPhaseEditItemReqVo::getWorkDate)).orElseThrow(() -> SyExceptionUtils.e("没有最小的交付日期")).getWorkDate();
        LocalDate endDate = reqVo.getItems().stream().max(Comparator.comparing(DayWorkOrderPhaseEditItemReqVo::getWorkDate)).orElseThrow(() -> SyExceptionUtils.e("没有最大的交付日期")).getWorkDate();

        // 初始化日历
        factoryCache.setMachines(stations.stream().map(AdoMachine::new).collect(Collectors.toList()));
        factoryCache.initDay(startDate, endDate);
        for (AdoMachine machine : factoryCache.getMachines()) {
            Integer totalWorkTime = machine.getWeekDays()
                    .stream()
                    .map(e -> shiftIdMap.get(e.getShiftId()).getTotalWorkTime())
                    .reduce(0, Integer::sum);

            Integer validTime = machine.getWeekDays()
                    .stream()
                    .map(e -> shiftIdMap.get(e.getShiftId()).getValidTime())
                    .reduce(0, Integer::sum);

            machine.setTotalWorkTime(totalWorkTime);
            machine.setValidTime(validTime);

        }

        Map<Integer, Group> groupIdMap = factoryCache.getGroups().stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        Map<String, List<AdoMachine>> groupCodeMachineMap = factoryCache.getMachines().stream().collect(Collectors.groupingBy(e -> groupIdMap.get(e.getStation().getGroupId()).getMyCode()));
        factoryCache.setGroupCodeMachineMap(groupCodeMachineMap);

        factoryCache.setIgnorePhaseCode(projectConig.getIgnorePhaseCodeList());
        List<Phase> phaseList = phaseMapper.lambdaQuery().isNotNull(Phase::getMyCode).isNotNull(Phase::getName).list();
        Map<String, Phase> phaseCodeMap = phaseList.stream().collect(Collectors.toMap(Phase::getMyCode, Function.identity()));
        factoryCache.setPhaseCodeMap(phaseCodeMap);

    }

    public void initOrderCache(AdoFactoryCache factoryCache, AdoOrderCache orderCache, ApsDayOrderPhaseEditReqVo reqVo) {
        Order order = orderMapper.lambdaQuery()
                .in(Order::getOrderType, ApsConstant.ORDER_TYPE_MAP.get("erp"))
                .ge(Order::getOrderStatus, 6)
                .eq(Order::getId, reqVo.getOrderId())
                .one();

        List<AdoOrderTemp> adoOrderTempList = reqVo.getItems()
                .stream()
                .map(e -> {
                    AdoOrder adoOrder = new AdoOrder();
                    adoOrder.setOrderId(reqVo.getOrderId());
                    adoOrder.setPhaseCode(reqVo.getPhaseCode());
                    adoOrder.setWorkDate(e.getWorkDate());
                    adoOrder.setTotalCount(e.getTotalCount());

                    AdoOrderTemp adoOrderTemp = new AdoOrderTemp();
                    adoOrderTemp.setAdoOrder(adoOrder);
                    return adoOrderTemp;
                })
                .collect(Collectors.toList());
        for (int i = 0; i < adoOrderTempList.size(); i++) {
            adoOrderTempList.get(i).setId(i + 1);
            adoOrderTempList.get(i).getAdoOrder().setSeq(i + 1);
        }
        orderCache.setAdoOrderTempList(adoOrderTempList);



        if (order == null) {
            throw SyExceptionUtils.e("没有待排产的订单");
        }

        List<OrderBom> orderBomList = orderBomMapper.lambdaQuery().eq(OrderBom::getOrderId, reqVo.getOrderId()).list();
        List<OrderPhase> orderPhaseList = orderPhaseMapper.lambdaQuery().eq(OrderPhase::getOrderId, reqVo.getOrderId()).list();

        orderCache.setOrder(order);
        orderCache.setOrderBomList(orderBomList);
        orderCache.setOrderPhaseList(orderPhaseList);

        List<String> primaryType = Arrays.asList("D", "Y", "Z");

        Map<Integer, OrderBom> orderBomMap = orderCache.getOrderBomList().stream().collect(Collectors.toMap(BaseEntity::getId, Function.identity()));
        OrderPhase currentPhase = null;
        if (primaryType.contains(order.getSuffix())) {
            Optional<OrderPhase> max = orderCache.getOrderPhaseList().stream().filter(e -> orderBomMap.get(e.getBomId()).getLevel() == (primaryType.contains(order.getSuffix()) ? 1 : 2)).max(Comparator.comparing(OrderPhase::getPhaseSeq));
            if(!max.isPresent()){
                throw SyExceptionUtils.e("没有找到顶层BOM的最后一道工序");
            }

            OrderPhase topBomLastPhase = max.get();

            // 先找到当前BOM，再找到子BOM，再找到父BOM
//            Integer workOrderCount = apsDayWorkOrderMapper.lambdaQuery().eq(ApsDayWorkOrder::getOrderId, reqVo.getOrderId()).count();
            Integer workOrderCount = adoWorkDetailMapper.lambdaQuery().eq(AdoWorkDetail::getOrderId, reqVo.getOrderId()).count();
            if (workOrderCount == 0 && !(reqVo.getPhaseCode().equals("PT") || reqVo.getPhaseCode().equals(topBomLastPhase.getPhaseCode()))) {
                throw SyExceptionUtils.e("首次只能调整PT和{}工序", topBomLastPhase.getPhaseCode());
            }

            if(reqVo.getPhaseCode().equals("PZ")){
                currentPhase = orderCache.getOrderPhaseList().stream().filter(e -> e.getPhaseCode().equals(reqVo.getPhaseCode()) && orderBomMap.get(e.getBomId()).getPlmId().contains("P1")).findFirst().get();
            } else if (reqVo.getPhaseCode().equals("WH") || reqVo.getPhaseCode().equals("ZT") || reqVo.getPhaseCode().equals("PT") || reqVo.getPhaseCode().equals("QM")){
                currentPhase = orderCache.getOrderPhaseList().stream().filter(e -> (reqVo.getPhaseCode().equals("QM") && e.getWorkGroupNumber().equals("4-2_QMGW_00")) || (!reqVo.getPhaseCode().equals("QM") && e.getPhaseCode().equals(reqVo.getPhaseCode()))).findFirst().get();
            } else {
                currentPhase = orderCache.getOrderPhaseList().stream().filter(e -> e.getPhaseCode().equals(reqVo.getPhaseCode()) &&  orderBomMap.get(e.getBomId()).getLevel() == 1).findFirst().get();
            }

        } else {
            currentPhase = orderCache.getOrderPhaseList().stream().filter(e -> orderBomMap.get(e.getBomId()).getLevel() == 1).max(Comparator.comparing(OrderPhase::getPhaseSeq)).get();
        }

        List<OrderBom> root = Collections.singletonList(orderBomMap.get(currentPhase.getBomId()));
        List<OrderPhase> editPhaseList = new ArrayList<>();


        Map<Integer, List<OrderPhase>> orderPhaseBomIdMap = orderCache.getOrderPhaseList().stream().collect(Collectors.groupingBy(OrderPhase::getBomId));
        Map<Integer, List<OrderBom>> orderBomPidMap = orderCache.getOrderBomList().stream().filter(e -> e.getPid() != null).collect(Collectors.groupingBy(OrderBom::getPid));

        while (CollUtil.isNotEmpty(root)) {

            List<OrderBom> temp = new ArrayList<>();
            for (OrderBom ob : root) {
                List<OrderPhase> orderPhases = orderPhaseBomIdMap.get(ob.getId());
                if(CollUtil.isEmpty(orderPhases)){
                    continue;
                }
                orderPhases.sort(Comparator.comparing(OrderPhase::getPhaseSeq).reversed());
                editPhaseList.addAll(orderPhases);

                List<OrderBom> orderBoms = orderBomPidMap.get(ob.getId());
                if(CollUtil.isNotEmpty(orderBoms)){
                    temp.addAll(orderBoms);
                }
            }

            root = temp;
        }

        dayWorkDetailMapper.lambdaUpdate()
                .in(AdoWorkDetail::getBomId, editPhaseList.stream().map(OrderPhase::getBomId).distinct().collect(Collectors.toList()))
                .remove();

//        List<DayWorkOrderPhaseEditItemReqVo> items = reqVo.getItems();
//        List<ApsDayOrder> collect = adoOrderTempList.stream()
//                .map(e -> {
//                    ApsDayOrder adoOrder = new ApsDayOrder();
//                    adoOrder.setOrderId(reqVo.getOrderId());
//                    adoOrder.setPhaseCode(reqVo.getPhaseCode());
//                    adoOrder.setWorkDate(e.getApsDayOrder().getWorkDate());
//                    adoOrder.setTotalCount(e.getApsDayOrder().getTotalCount());
//                    return adoOrder;
//                })
//                .collect(Collectors.toList());
//        for (int i = 0; i < collect.size(); i++) {
//            collect.get(i).setSeq(i+1);
//        }

//        orderCache.setDayOrderList(collect);

        Map<Integer, OrderPhase> orderPhaseIdMap = orderPhaseList.stream().collect(Collectors.toMap(e -> e.getId(), e -> e));
        List<AdoWorkDetailTemp> workDetailTempList = editPhaseList.stream()
                .flatMap(e ->
                        adoOrderTempList.stream()
                                .map(e1 -> {
                                    OrderBom orderBom = orderBomMap.get(e.getBomId());
                                    AdoWorkDetail awd = new AdoWorkDetail();
                                    awd.setOrderId(e.getOrderId());
                                    awd.setBomId(e.getBomId());
                                    awd.setBomPid(orderBom.getPid());
                                    awd.setPhaseId(e.getId());
                                    awd.setPartCount(orderBom.getPartCount());
                                    awd.setTotalCount(orderBom.getTotalCount());
                                    awd.setOrderCount(new BigDecimal(e1.getAdoOrder().getTotalCount()).multiply(orderBom.getTotalCount()));
                                    awd.setPlmId(orderBom.getPlmId());
                                    awd.setMaterName(orderBom.getMaterName());
                                    awd.setGroupCode(e.getWorkGroupNumber());
                                    awd.setPhaseCode(e.getPhaseCode());
                                    awd.setPhaseName(e.getPhaseName());
                                    awd.setPhaseSeq(e.getPhaseSeq());
                                    awd.setWorkTime(e.getWorkTime());
                                    awd.setType(2);
                                    awd.setOrderType(order.getOrderType());
                                    awd.setStatus(1);

                                    AdoWorkDetailTemp temp = new AdoWorkDetailTemp();
//                                    temp.setApsDayOrder(e1);
                                    temp.setOrderBom(orderBom);
                                    temp.setOrderPhase(orderPhaseIdMap.get(awd.getPhaseId()));
                                    temp.setWorkDetail(awd);
                                    temp.setAdoOrderTemp(e1);
                                    return temp;
                                })
                )
                .filter(e -> !e.getWorkDetail().getPhaseCode().equals("PP"))
                .collect(Collectors.toList());

        List<AdoTask> taskList = workDetailTempList.stream()
                .map(e -> {
                    AdoTask t = new AdoTask(e.getWorkDetail());
                    t.setWorkDetailTemp(e);
                    t.setId(e.getWorkDetail().getId());
                    t.setConsumerStatus(1);
                    t.setConsumerCount(new BigDecimal(0));
                    t.setStatus(2);
                    return t;
                })
                .collect(Collectors.toList());
        orderCache.setTaskList(taskList);


        orderCache.setOrderBomIdMap(orderCache.getOrderBomList().stream().collect(Collectors.toMap(BaseEntity::getId, e->e)));


    }

    public void unlock(ApsDayOrderPhaseEditReqVo reqVo) {
        stringRedisTemplate.delete(ApsConstant.APS_SCHEDULING_LOCK);
    }
}
